using Microsoft.Extensions.Logging;
using StackExchange.Redis;
using System.Text.Json;

namespace BW.WMS.Infrastructure.Services
{
    public class RedisCacheService : IRedisCacheService
    {
        private readonly IConnectionMultiplexer _connectionMultiplexer;
        private readonly IDatabase _database;
        private readonly ILogger<RedisCacheService> _logger;
        private readonly JsonSerializerOptions _jsonOptions;

        public RedisCacheService(IConnectionMultiplexer connectionMultiplexer, ILogger<RedisCacheService> logger)
        {
            _connectionMultiplexer = connectionMultiplexer;
            _database = _connectionMultiplexer.GetDatabase(0); // 明确指定数据库0，兼容集群模式
            _logger = logger;
            _jsonOptions = new JsonSerializerOptions
            {
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                PropertyNameCaseInsensitive = true
            };
        }

        public async Task<bool> SetStringAsync(string key, string value, TimeSpan? expiry = null)
        {
            try
            {
                return await _database.StringSetAsync(key, value, expiry);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error setting string cache for key: {Key}", key);
                return false;
            }
        }

        public async Task<string?> GetStringAsync(string key)
        {
            try
            {
                var value = await _database.StringGetAsync(key);
                return value.HasValue ? value.ToString() : null;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting string cache for key: {Key}", key);
                return null;
            }
        }

        public async Task<bool> SetAsync<T>(string key, T value, TimeSpan? expiry = null)
        {
            try
            {
                var jsonString = JsonSerializer.Serialize(value, _jsonOptions);
                return await _database.StringSetAsync(key, jsonString, expiry);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error setting object cache for key: {Key}", key);
                return false;
            }
        }

        public async Task<T?> GetAsync<T>(string key)
        {
            try
            {
                var value = await _database.StringGetAsync(key);
                if (!value.HasValue)
                    return default;

                return JsonSerializer.Deserialize<T>(value!, _jsonOptions);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting object cache for key: {Key}", key);
                return default;
            }
        }

        public async Task<bool> DeleteAsync(string key)
        {
            try
            {
                return await _database.KeyDeleteAsync(key);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error deleting cache for key: {Key}", key);
                return false;
            }
        }

        public async Task<long> DeleteAsync(IEnumerable<string> keys)
        {
            try
            {
                var redisKeys = keys.Select(key => (RedisKey)key).ToArray();
                return await _database.KeyDeleteAsync(redisKeys);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error deleting batch cache for keys: {Keys}", string.Join(", ", keys));
                return 0;
            }
        }

        public async Task<bool> ExistsAsync(string key)
        {
            try
            {
                return await _database.KeyExistsAsync(key);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error checking existence for key: {Key}", key);
                return false;
            }
        }

        public async Task<bool> ExpireAsync(string key, TimeSpan expiry)
        {
            try
            {
                return await _database.KeyExpireAsync(key, expiry);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error setting expiry for key: {Key}", key);
                return false;
            }
        }

        public async Task<TimeSpan?> GetExpireAsync(string key)
        {
            try
            {
                return await _database.KeyTimeToLiveAsync(key);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting expiry for key: {Key}", key);
                return null;
            }
        }

        public async Task<bool> HashSetAsync(string key, string field, string value)
        {
            try
            {
                return await _database.HashSetAsync(key, field, value);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error setting hash field for key: {Key}, field: {Field}", key, field);
                return false;
            }
        }

        public async Task<string?> HashGetAsync(string key, string field)
        {
            try
            {
                var value = await _database.HashGetAsync(key, field);
                return value.HasValue ? value.ToString() : null;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting hash field for key: {Key}, field: {Field}", key, field);
                return null;
            }
        }

        public async Task<bool> HashDeleteAsync(string key, string field)
        {
            try
            {
                return await _database.HashDeleteAsync(key, field);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error deleting hash field for key: {Key}, field: {Field}", key, field);
                return false;
            }
        }

        public async Task<long> ListLeftPushAsync(string key, string value)
        {
            try
            {
                return await _database.ListLeftPushAsync(key, value);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error left pushing to list for key: {Key}", key);
                return 0;
            }
        }

        public async Task<long> ListRightPushAsync(string key, string value)
        {
            try
            {
                return await _database.ListRightPushAsync(key, value);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error right pushing to list for key: {Key}", key);
                return 0;
            }
        }

        public async Task<string?> ListLeftPopAsync(string key)
        {
            try
            {
                var value = await _database.ListLeftPopAsync(key);
                return value.HasValue ? value.ToString() : null;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error left popping from list for key: {Key}", key);
                return null;
            }
        }

        public async Task<string?> ListRightPopAsync(string key)
        {
            try
            {
                var value = await _database.ListRightPopAsync(key);
                return value.HasValue ? value.ToString() : null;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error right popping from list for key: {Key}", key);
                return null;
            }
        }

        public async Task<long> ListLengthAsync(string key)
        {
            try
            {
                return await _database.ListLengthAsync(key);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting list length for key: {Key}", key);
                return 0;
            }
        }
    }
}